import { isEqual } from "lodash-es";
import type { DrawerInstance, DrawerProps, ReturnMethods, UseDrawerInnerReturnType, UseDrawerReturnType } from "./typing";
import { isProdMode } from "@/utils/env";
import { isFunction } from "@/utils/is";
import { useEffect, useMemo, useRef, useState } from "react";

const dataTransferRef: any = {};
const openData: { [key: number]: boolean } = {};

/**start-@updateBy:Jok-2024/12/16-11:42-解决数据响应式问题，否则openDrawer时传值无法在抽屉详情获取 */
function useStoreData(callback?: Fn) {
	const [drawerData, setDrawerData] = useState<any>({});

	useEffect(() => {
		callback && callback();
	}, [drawerData, callback]);

	return { drawerData, setDrawerData };
}
/**end-@updateBy:Jok-2024/12/16-11:42-解决数据响应式问题，否则openDrawer时传值无法在抽屉详情获取 */

/**
 * @description: Applicable to separate drawer and call outside
 */
export function useDrawer(): UseDrawerReturnType {
	const drawer = useRef<DrawerInstance | null>(null);
	const loaded = useRef<Nullable<boolean>>(false);
	const uid = useRef<number>(0);
	const { setDrawerData } = useStoreData();

	function register(drawerInstance: DrawerInstance, uuid: number) {
		if (loaded.current && isProdMode() && drawerInstance === drawer.current) return;

		uid.current = uuid;
		drawer.current = drawerInstance;
		loaded.current = true;

		drawerInstance.emitOpen = (open: boolean, uid: number) => {
			openData[uid] = open;
		};
	}

	const getInstance = () => {
		const instance = drawer.current;
		if (!instance) console.error("useDrawer instance is undefined!");

		return instance;
	};

	const methods: ReturnMethods = {
		setDrawerProps: (props: Partial<DrawerProps>) => {
			getInstance()?.setDrawerProps(props);
		},

		getOpen: useMemo((): boolean => {
			return openData[~~uid.current];
		}, [uid.current]),

		openDrawer: <T = any>(open = true, data?: T, openOnSet = true): void => {
			getInstance()?.setDrawerProps({
				open
			});
			if (!data) return;
			if (openOnSet) {
				dataTransferRef[uid.current] = null;
				dataTransferRef[uid.current] = data;
				setDrawerData({
					...dataTransferRef,
					[uid.current]: data
				});
				return;
			}
			const equal = isEqual(dataTransferRef[uid.current], data);
			if (!equal) dataTransferRef[uid.current] = data;
		},
		closeDrawer: () => {
			getInstance()?.setDrawerProps({ open: false });
		}
	};

	return [register, methods];
}

export function useDrawerInner(emitFunc: Fn, callbackFn?: Fn): UseDrawerInnerReturnType {
	const drawerInstanceRef = useRef<Nullable<DrawerInstance>>(null);
	const uidRef = useRef<number>(0);

	useStoreData(() => {
		const data = dataTransferRef[uidRef.current];
		if (!data) return;
		if (!callbackFn || !isFunction(callbackFn)) return;
		callbackFn(data);
	});

	const getInstance = () => {
		const instance = drawerInstanceRef.current;
		if (!instance) {
			console.error("useDrawerInner instance is undefined!");
			return;
		}
		return instance;
	};

	const register = (modalInstance: DrawerInstance, uuid: number) => {
		uidRef.current = uuid;
		drawerInstanceRef.current = modalInstance;
		// like emit of Vue
		emitFunc && emitFunc(modalInstance, uuid);
	};

	return [
		register,
		{
			changeLoading: (loading = true) => {
				getInstance()?.setDrawerProps({ loading });
			},

			changeOkLoading: (loading = true) => {
				getInstance()?.setDrawerProps({ confirmLoading: loading });
			},
			getOpen: useMemo((): boolean => {
				return openData[~~uidRef.current];
			}, [uidRef.current]),

			closeDrawer: () => {
				getInstance()?.setDrawerProps({ open: false });
			},

			setDrawerProps: (props: Partial<DrawerProps>) => {
				getInstance()?.setDrawerProps(props);
			}
		}
	];
}
